package lab2rsagroup10;

import java.math.BigInteger;

/**
 * 
 * Tries to break a RSA cipher.
 *
 */
public class RSABreaker {
	
	/** The RSA modulos.*/
	private final BigInteger n_;
	private final CipherTable table_;
	
	/**
	 * Breaker constructor.
	 * @param publicKey - The public RSA key.
	 * @param modulos - The RSA modulos.
	 * @param r - The number of bits used for the message to be decrypted.
	 */
	public RSABreaker(RSA.Key publicKey, int r){
		n_ = publicKey.modulos;
		final int num_entries = 1 << r;
		
		table_ = new CipherTable(num_entries);
		
		//Populate cipher table with possible ciphertexts
		BigInteger entry = BigInteger.ONE;
		BigInteger c;
		for (int i = 0; i < num_entries; ++i) {
			c = RSA.encrypt(entry, publicKey);
			table_.addEntry(c, Util.inv(c, n_));
			entry = entry.add(BigInteger.ONE);
		}
		
		table_.sortEntries();
	}
	
	/**
	 * Tries to break the RSA cipher by exploiting the fact that short messages
	 * makes it easier to find the message.
	 * @param cipher - The encrypted message.
	 * @return The decrypted message. Returns <code>null</code> if the 
	 * decrypted message could not be found.
	 */
	public String findMessage(final BigInteger cipher) {
		BigInteger entry;
		CipherTable.Entry found;
		
		for (CipherTable.Entry e : table_) {
			entry = cipher.multiply(e.inverseEntry).mod(n_);
			found = table_.lookUpEntry(entry);
			if (found != null) {
				//We found the message
				return new String(e.index.multiply(found.index).toByteArray());
			}
		}
		
		return null;
	}
}
